package com.joven.product.api.infrastructure.common.exception;

import com.joven.infra.common.exception.ApiException;
import com.joven.infra.common.model.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;

/**
 * 全局异常处理
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {


    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public Response<Object> handle(Exception e) {
        log.error(e.getMessage(), e);
        return Response.failed("系统异常！");
    }

    @ResponseBody
    @ExceptionHandler(value = ConstraintViolationException.class)
    public Response<Object> handle(ConstraintViolationException e) {
        log.error("参数校验失败," + e.getMessage(), e);
        return Response.illegalArgument(e.getConstraintViolations().stream().map(it->it.getMessage()).collect(Collectors.joining("/")));
    }

    @ResponseBody
    @ExceptionHandler(IllegalArgumentException.class)
    public Response<Object> handle(IllegalArgumentException e) {
        log.error("参数校验失败," + e.getMessage(), e);
        return Response.illegalArgument(e.getMessage());
    }

    @ResponseBody
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public Response<Object> handleValidException(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        String logMessage = null;
        FieldError fieldError = bindingResult.getFieldError();
        if (fieldError != null) {
            logMessage = fieldError.getField() + fieldError.getDefaultMessage();
        }
        return Response.illegalArgument(logMessage);
    }

    @ResponseBody
    @ExceptionHandler(value = BindException.class)
    public Response<Object> handleValidException(BindException e) {
        BindingResult bindingResult = e.getBindingResult();
        String message = null;
        String logMessage = null;
        if (bindingResult.hasErrors()) {
            FieldError fieldError = bindingResult.getFieldError();
            if (fieldError != null) {
                message = fieldError.getDefaultMessage();
                logMessage = fieldError.getField() + fieldError.getDefaultMessage();
            }
        }
        log.error(logMessage, e);
        return Response.illegalArgument(message);
    }

    /**
     * 缺少请求体异常处理器
     *
     * @param e
     * @return ResponseResult
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public Response<Object> parameterMissingExceptionHandler(MissingServletRequestParameterException e) {
        log.info("忽略参数异常", e);
        return Response.illegalArgument("请求参数[" + e.getParameterName() + "]不能为空");
    }


    /**
     * 请求参数格式错误
     *
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Response<Object> parameterBodyMissingExceptionHandler(HttpMessageNotReadableException e) {
        log.info("请求参数格式错误", e);
        return Response.illegalArgument("请求参数格式错误");
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(RuntimeException.class)
    public Response<Object> innerServerExceptionHandler(RuntimeException e) {
        log.error("系统内部异常", e);
        return Response.failed("系统内部异常");
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(ApiException.class)
    public Response<Object> innerServerExceptionHandler(ApiException e) {
        log.error("业务异常", e);
        return Response.builder().code(e.getCode()).message(e.getMessage()).build();
    }
}
